<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <style></style>
  </head>
  <body>
    <div></div>
    <script>
      const PENDING = "pending"; //等待
      const FULFILLED = "FULFILLED"; //成功
      const REJECTED = "rejected"; //失败

      class MyPromise {
        constructor(executor) {
          // 用于捕获执行器状态
          try {
            //   这里是调用执行器
            executor(this.resolve, this.reject);
          } catch (e) {
            this.reject(e);
          }
        }
        //peomise状态
        status = PENDING;
        //成功之后的值
        value = undefined;
        //失败之后的原因
        reason = undefined;
        //成功回调,用数组的原因是多次调用是会产生多个回调函数需要存储多个回调函数
        successCallback = [];
        //失败回调,用数组的原因是多次调用是会产生多个回调函数需要存储多个回调函数
        failCallback = [];
        resolve = (value) => {
          //如果状态不是等待  阻止程序向下执行
          if (this.status !== PENDING) return;
          //将状态更改为成功
          this.status = FULFILLED;
          //保存成功之后的值
          this.value = value;
          //判断成功回调是否存在  如果存在  调用
          //   this.successCallback && this.successCallback(this.value);
          while (this.successCallback.length) {
            //shift的返回值是弹出的函数
            this.successCallback.shift()();
          }
        };
        reject = (reason) => {
          //如果状态不是等待  阻止程序向下执行
          if (this.status !== PENDING) return;
          //将状态更改为失败
          this.status = REJECTED;
          //   保存失败的原因
          this.reason = reason;
          //判断失败回调是否存在  如果存在  调用
          //   this.failCallback && this.failCallback(this, reason);
          while (this.failCallback.length) {
            this.failCallback.shift()();
          }
        };
        then(successCallback, failCallback) {
          //判断是否有回调函数，没有就补，then底链式调用如果前面底then都没有回调函数，promise的状态回依次向后传递，找到第一个带回调函数的then方法，promise的状态也可以一直向后传递，每次then方法return该状态即可（前面的then可以不传递参数，后面的then也能拿到值）
          successCallback = successCallback
            ? successCallback
            : (value) => value;

          failCallback = failCallback
            ? failCallback
            : (reason) => {
                throw reason;
              };
          //创建一个promise对象是让then方法可以链式调用
          let promise2 = new MyPromise((resolve, reject) => {
            //判断状态
            if (this.status === FULFILLED) {
              // 用异步代码的作用是让promise2  执行完成  否则获取不到rromise2对象 不能通过
              setTimeout(() => {
                //成功则调用成功的回调函数并且传递参数
                //把值存储在x中目的是传给下一个then、
                try {
                  let x = successCallback(this.value);

                  //1.判断x的值是普通值还是promise对象
                  //2.如果是普通值  直接调用resolve
                  //3.如果是promise对象  查看promise对象返回的结果
                  //4.再根据promise对象返回的结果  决定调用resolve还是调用reject
                  //   resolve(x);
                  //   x和promise2是用于判断then链式调用是否返回了当前promise对象
                  resolvePromise(x, promise2, resolve, reject);
                } catch (e) {
                  // 因为如果成功回调函数发生异常的话手动调用reject
                  //把错误传递给下一个then
                  reject(e);
                }
              }, 0);
            } else if (this.status === REJECTED) {
              setTimeout(() => {
                try {
                  //   失败则调用失败函数并且传递函数
                  let x = failCallback(this.reason);

                  //1.判断x的值是普通值还是promise对象
                  //2.如果是普通值  直接调用resolve
                  //3.如果是promise对象  查看promise对象返回的结果
                  //4.再根据promise对象返回的结果  决定调用resolve还是调用reject
                  //   resolve(x);
                  //   x和promise2是用于判断then链式调用是否返回了当前promise对象
                  resolvePromise(x, promise2, resolve, reject);
                } catch (e) {
                  // 因为如果成功回调函数发生异常的话手动调用reject
                  //把错误传递给下一个then
                  reject(e);
                }
              }, 0);
            } else {
              //如果状态是等待则将成功和失败的回调函数存储起来
              //等待异步
              //将成功回调和失败回调存储起来
              this.successCallback.push(() => {
                // successCallback();
                setTimeout(() => {
                  //成功则调用成功的回调函数并且传递参数
                  //把值存储在x中目的是传给下一个then、
                  try {
                    let x = successCallback(this.value);

                    //1.判断x的值是普通值还是promise对象
                    //2.如果是普通值  直接调用resolve
                    //3.如果是promise对象  查看promise对象返回的结果
                    //4.再根据promise对象返回的结果  决定调用resolve还是调用reject
                    //   resolve(x);
                    //   x和promise2是用于判断then链式调用是否返回了当前promise对象
                    resolvePromise(x, promise2, resolve, reject);
                  } catch (e) {
                    // 因为如果成功回调函数发生异常的话手动调用reject
                    //把错误传递给下一个then
                    reject(e);
                  }
                }, 0);
              });
              this.failCallback.push(() => {
                setTimeout(() => {
                  try {
                    //   失败则调用失败函数并且传递函数
                    let x = failCallback(this.reason);

                    //1.判断x的值是普通值还是promise对象
                    //2.如果是普通值  直接调用resolve
                    //3.如果是promise对象  查看promise对象返回的结果
                    //4.再根据promise对象返回的结果  决定调用resolve还是调用reject
                    //   resolve(x);
                    //   x和promise2是用于判断then链式调用是否返回了当前promise对象
                    resolvePromise(x, promise2, resolve, reject);
                  } catch (e) {
                    // 因为如果成功回调函数发生异常的话手动调用reject
                    //把错误传递给下一个then
                    reject(e);
                  }
                }, 0);
              });
            }
          });
          return promise2;
        }
        finally(callback) {
          //return  的目的是返回一个promise对象，方便后面then方法实现链式调用
          //then方法传入两个函数，一个成功一个失败
          return this.then(
            (value) => {
              return MyPromise.resolve(callback()).then(() => value);
              // callback();
              //目的是返回结果给下一个then
              // return value;
            },
            (reason) => {
              return MyPromise.resolve(callback()).then(() => {
                throw reason;
              });
              // callback();
              // throw reason;
            }
          );
        }

        catch(failCallback) {
          return this.then(undefined, failCallback);
        }
        static all(array) {
          let result = [];
          let index = 0;

          return new MyPromise((resolve, reject) => {
            function addData(key, value) {
              result[key] = value;
              //设置index的目的是解决异步的问题
              index++;
              if (index === array.length) {
                // 在执行一遍
                resolve(result);
              }
            }
            for (let i; i < array.length; i++) {
              //获取当前值
              let current = array[i];
              if (current instanceof MyPromise) {
                //promise对象
                current.then(
                  (value) => {
                    addData(i, value);
                  },
                  (err) => {
                    reject(err);
                  }
                );
              } else {
                //普通值
                addData(i, array[i]);
              }
            }
            resolve(result);
          });
        }
        static resolve(value) {
          if (value instanceof MyPromise) return value;
          return new MyPromise((resolve) => {
            resolve(value);
          });
        }
      }

      function resolvePromise(x, promise2, resolve, reject) {
        if (x === promise2) {
          // 两者相等代表then方法返回了当前的promise对象
          //return用于阻止代码向下执行
          return reject(
            new TypeError("Chaining cycle detected for promise #<Promise>")
          );
        }
        //判断x是否为promise对象
        if (x instanceof MyPromise) {
          //   x.then((value) => resolve(value, (reason) => reject(reason)));
          //等同于上面的
          x.then(resolve, reject);
        } else {
          //x为普通值
          resolve(x);
        }
      }
    </script>
  </body>
</html>
